package com.lagou.filters;

import com.lagou.bean.TPMonitor;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @Author : liuchangling
 * @Descrition :
 * @Date： Created in 3:41 下午 2021/12/27
 */
@Activate(group = {CommonConstants.CONSUMER})
public class TPMonitorFilter implements Filter, Runnable {
    Map<String, List<TPMonitor>> methodTimes = new ConcurrentHashMap<>();

    {
        Executors.newSingleThreadScheduledExecutor()
                .scheduleWithFixedDelay(this, 5, 5, TimeUnit.SECONDS);
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long startTime = System.currentTimeMillis();
        Result result = invoker.invoke(invocation);
        long endTime = System.currentTimeMillis();
        TPMonitor tpMonitor = new TPMonitor();
        tpMonitor.setMethodName(invocation.getMethodName());
        tpMonitor.setRunTime(endTime - startTime);
        tpMonitor.setEndTime(endTime);
        String methodName = invocation.getMethodName();
        System.out.println("method=" + methodName + "消耗的时间:" + (endTime - startTime) + "毫秒");

        //如果是第一次执行，则对其进行初始化，key为methodName，value为list
        List<TPMonitor> list = methodTimes.get(methodName);
        if (list == null) {
            list = new ArrayList<>();
            methodTimes.put(methodName, list);
        }
        list.add(tpMonitor);
        return result;
    }

    @Override
    public void run() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String dateStr = sdf.format(date);

        for (Map.Entry<String, List<TPMonitor>> methodInfos : methodTimes.entrySet()) {
            System.out.println(dateStr + methodInfos.getKey() + "的TP90:" + getTP(methodInfos.getValue(), 0.9) + "毫秒,"
                    + "TP99:" + getTP(methodInfos.getValue(), 0.99) + "毫秒");
        }
    }

    private Long getTP(List<TPMonitor> list, double rate) {
        List<TPMonitor> listTP = new ArrayList<>();
        long endTime = System.currentTimeMillis();
        long startTime = System.currentTimeMillis() - 60000;

        int length = list.size();
        //将满足1分钟之内的TPMonitor添加到listTP中
        for (int i = 0; i < length; i++) {
            TPMonitor tpMonitor = list.get(i);
            if (tpMonitor.getEndTime() >= startTime && tpMonitor.getEndTime() <= endTime) {
                listTP.add(tpMonitor);
            }
        }

        listTP.sort(new Comparator<TPMonitor>() {
            @Override
            public int compare(TPMonitor tpMonitor, TPMonitor t1) {
                if (tpMonitor.getRunTime() > t1.getRunTime()) {
                    return 1;
                } else if (tpMonitor.getRunTime() < t1.getRunTime()) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });

        //获取当前排序后集合中的指定百分比数值的位置，此位置存储的数据就是当前计算的tp90/99
        int index = (int) (listTP.size() * rate);
        return listTP.get(index).getRunTime();
    }
}
